use core::u32;

use crate::fs::block::{Block, BlockManager, BLOCK_SIZE};
use alloc::{sync::Arc, vec::Vec};
use spin::Mutex;

/// FAT 是由若干个扇区组成的表
/// 表中每四个字节（小端格式）表示一个簇编号
/// 例如FAT中下标i对应的四字节j，表示簇i的下一个
/// 簇是簇j
pub struct Fat {
    pub(crate) start_block_id: usize,
    //block_ids: Vec<usize>,
    pub(crate) ids_per_block: usize,
    pub(crate) max_cluster_id: usize,
    pub(crate) block_manager: Arc<BlockManager>,

    // 这里自定义一些会用到的字段
    // 物理设备的最小读取单元可能与
    // 系统定义的最小单元Block 大小不相同
    // 所以需要做一下转换
    //pub(crate) blocks_per_sector: usize,
    pub(crate) blocks_offset_to_data: usize,
    pub(crate) blocks_per_cluster: usize,
}

impl Fat {
    pub fn next_cluster_id(&self, cluster_id: usize) -> Option<usize> {
        if cluster_id > self.max_cluster_id {
            None
        } else {
            let mut blk_id_offset: usize = 0;
            let mut res_id = cluster_id;
            loop {
                if res_id >= self.ids_per_block {
                    blk_id_offset += 1;
                    res_id -= self.ids_per_block;
                } else {
                    break;
                }
            }
            let goal_blk_id = self.start_block_id + blk_id_offset;
            let mut tmp_blk = Block {
                id: 0,
                data: [0; BLOCK_SIZE],
            };
            //let mut buf = [0; BLOCK_SIZE];
            self.block_manager
                .read_block(goal_blk_id, &mut tmp_blk.data);
            tmp_blk.use_as(res_id * 4, |next_id: &[u8; 4]| {
                let n_id = u32::from_le_bytes(next_id.clone());
                if n_id >= 0x0FFFFFF8 {
                    None
                } else {
                    Some(n_id as usize)
                }
            })
        }
    }
}
